﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Utility
{
    public class SG90Rotation180
    {
        /// <summary>
        /// 脉冲频率(Hz)
        /// </summary>
        private int Frequency = 50;

        /// <summary>
        /// 步进转动间隔(度)
        /// </summary>
        private double Delta_theta = 0.2;

        /// <summary>
        /// 转动delta_theta的理论耗时(毫秒)理论耗时0.6毫秒！！
        /// </summary>
        private int Min_delay = 1;

        /// <summary>
        /// 0转到180的耗时(毫秒)
        /// </summary>
        private int Max_delay = 400;

        /// <summary>
        /// 舵机信号线所连接的树莓派引脚编号（BCM编码）
        /// </summary>
        private int Channel;

        /// <summary>
        /// 舵机转动的最小角度
        /// </summary>
        private int Min_theta;

        /// <summary>
        /// 舵机转动的最大角度
        /// </summary>
        private int Max_theta;

        /// <summary>
        /// 最小角度占空比
        /// </summary>
        private double Min_dutycycle;

        /// <summary>
        /// 最大角度的占空比
        /// </summary>
        private double Max_dutycycle;

        /// <summary>
        /// 舵机的初始角度
        /// </summary>
        private int Init_theta;


        private double Dutycycle;

        public SG90Rotation180() { }

        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="channel">舵机信号线所连接的树莓派引脚编号（BCM编码）</param>
        /// <param name="min_thete">舵机转动的最小角度</param>
        /// <param name="max_theta">舵机转动的最大角度</param>
        /// <param name="init_theta">舵机的初始角度</param>
        public SG90Rotation180(int channel,int min_thete,int max_theta,int init_theta) 
        {
            this.Channel = channel;
            if (min_thete < 0 || min_thete > 180)
                this.Min_theta = 0;
            else
                this.Min_theta = min_thete;

            if (max_theta < 0 || max_theta > 180)
                this.Max_theta = 180;
            else
                this.Max_theta = max_theta;

            if (init_theta < min_thete || init_theta > max_theta)
                this.Init_theta = (this.Min_theta + this.Max_theta) / 2;
            else
                this.Init_theta = init_theta;//初始角度

            //计算最小角度、最大角度的占空比
            this.Min_dutycycle = 2.5 + this.Min_theta * 10 / 180;
            this.Max_dutycycle = 2.5 + this.Max_theta * 10 / 180;
        }


        /// <summary>
        /// 初始化设置
        /// </summary>
        /// <returns></returns>
        public bool Setup() 
        {
            //设置BCM模式（需要ROOT权限）
            if (GPIO.WiringPiSetupGpio() == -1)
               return false;
            //将引脚设置为输出模式
            GPIO.PinMode(this.Channel, WiringPi.Output);
            GPIO.SoftPwmCreate(this.Channel,this.Frequency,1024);
            this.Dutycycle = 2.5 + this.Init_theta * 10 / 180; //脉冲占空比的初始值
            GPIO.SoftPwmWrite(this.Channel,Convert.ToInt32(this.Dutycycle)); //让舵机转到初始位置
            Thread.Sleep(Max_delay);
            return true;
        }

        /// <summary>
        /// 正相步进转动，每次调用只转动delta_theta度
        /// </summary>
        public void PositiveRotation() 
        {
            this.Dutycycle = this.Dutycycle + this.Delta_theta * 10 / 180;
            if (this.Dutycycle > this.Max_dutycycle)
                this.Dutycycle = this.Max_dutycycle;
            GPIO.SoftPwmWrite(this.Channel,Convert.ToInt32(this.Dutycycle));
            Thread.Sleep(Min_delay);
        }

        /// <summary>
        /// 反相转动，每次调用只转动delta_theta度
        /// </summary>
        public void ReverseRotation() 
        {
            this.Dutycycle = this.Dutycycle - this.Delta_theta * 10 / 180;
            if (this.Dutycycle < this.Min_dutycycle)
                this.Dutycycle = this.Min_dutycycle;
            GPIO.SoftPwmWrite(this.Channel,Convert.ToInt32(this.Dutycycle));
            Thread.Sleep(this.Min_delay);
        }


        /// <summary>
        /// 转动到指定的角度
        /// </summary>
        /// <param name="theta">角度</param>
        public void SpecifyRotation(int theta) 
        {
            if (theta < 0 || theta > 180)
                return;
            this.Dutycycle = 2.5 + theta * 10 / 180;
            GPIO.SoftPwmWrite(this.Channel,Convert.ToInt32(this.Dutycycle));
            Thread.Sleep(this.Max_delay);
        }
    }
}
